package com.hjy.im.server;

import com.hjy.im.message.ChatRequestMessage;
import com.hjy.im.message.GroupChatRequestMessage;
import com.hjy.im.protocol.MessageSharableCodec;
import com.hjy.im.protocol.ProcotolFrameDecoder;
import com.hjy.im.server.handler.*;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ChatServer {
    static final Logger log = LoggerFactory.getLogger(ChatServer.class);
    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        LoggingHandler loggingHandler = new LoggingHandler(LogLevel.DEBUG);
        LoginRequestMessageHandler loginRequestMessageHandler = new LoginRequestMessageHandler();
        MessageSharableCodec messageSharableCodec = new MessageSharableCodec();
        ChatRequestMessageHandler chatRequestMessageHandler = new ChatRequestMessageHandler();
        GroupCreateRequestMessageHandler createRequestMessageHandler = new GroupCreateRequestMessageHandler();
        GroupChatRequestMessageHandler groupChatRequestMessageHandler = new GroupChatRequestMessageHandler();
        QuitHandler quitHandler = new QuitHandler();
        RpcRequestMessageHandler rpcRequestMessageHandler = new RpcRequestMessageHandler();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss, worker);
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    // 用来判断 是不是读 空闲时间过长，或写空闲时间过长 (读，写，读写空闲时间限制) 0表示不关心
                    ch.pipeline().addLast(new IdleStateHandler(12, 0, 0));
                    /*
                    ################################################################
                    #####  ChannelDuplexHandler 可以同时作为 入站 和 出站处理器  #######
                    ##### 12 秒内 没读到数据 触发   IdleState.READER_IDLE       #######
                    #####       写         触发   IdleState.WRITER_IDLE       #######
                    #####     读写         触发   IdleState.ALL_IDLE          #######
                    ################################################################
                     */
                    ch.pipeline().addLast(new ChannelDuplexHandler(){
                        @Override
                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                            //用来处理读写之外的特殊事件
                            IdleStateEvent evnet = (IdleStateEvent) evt;
                            //是否读超时
                            if (evnet.state() == IdleState.READER_IDLE){
                                log.debug("===========12 秒没有读到数据了");
                                ctx.channel().close();
                            }
                        }
                    });
                    ch.pipeline().addLast(quitHandler);//    断开链接 处理器
                    ch.pipeline().addLast(new ProcotolFrameDecoder()); //帧解码器  【与自定义编解码器 MessageCodecSharable一起配置参数】
                    ch.pipeline().addLast(loggingHandler);  //日志
                    ch.pipeline().addLast(rpcRequestMessageHandler); //添加支持rpc 协议
                    ch.pipeline().addLast(messageSharableCodec);//出入站自定义编解码器
                    ch.pipeline().addLast(loginRequestMessageHandler);//登录处理器
                    ch.pipeline().addLast(chatRequestMessageHandler);//单聊处理器
                    ch.pipeline().addLast(createRequestMessageHandler);//群聊创建处理器
                    ch.pipeline().addLast(groupChatRequestMessageHandler);//群聊处理器

                }
            });
            Channel channel = bootstrap.bind(9090).sync().channel();
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}